﻿using AutoMapper;
using DFGK.IRepository;
using DFGK.IService;
using DFGK_WMS.Model.Dto;
using DFGK_WMS.Model.Exports;
using DFGK_WMS.Model.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace DFGK.Service
{
    public class InventoryService : BaseService, IInventoryService
    {
        private readonly IShippingReplenishmentRepository _shippingReplenishmentRepository;
        private readonly IMaterialPackageRepository _materialPackageRepository;
        private readonly IInventoryRepository _inventoryRepository;
        private readonly IMaterialRepository _materialRepository;
        private readonly IPalletRepository _palletRepository;
        private readonly IUnitOfWork _unitOfWork;
        public InventoryService(IMapper mapper, IInventoryRepository inventoryRepository, IMaterialRepository materialRepository, IPalletRepository palletRepository, IUnitOfWork unitOfWork, IMaterialPackageRepository materialPackageRepository, IShippingReplenishmentRepository shippingReplenishmentRepository) : base(mapper)
        {
            _shippingReplenishmentRepository = shippingReplenishmentRepository;
            _materialPackageRepository = materialPackageRepository;
            _inventoryRepository = inventoryRepository;
            _materialRepository = materialRepository;
            _palletRepository = palletRepository;
            _unitOfWork = unitOfWork;
        }

        public List<Inventory> GetInventoryDetailList(string? ModelSpec,string? StockName,string? mname, int status, int pageIndex, int pageSize, out int totalCount)
        {
            var list = _inventoryRepository.GetEntityAlls();
            if(!string.IsNullOrEmpty(ModelSpec))
                list = list.Where(x => x.MaterialCategoryName.Contains(ModelSpec));

            if (!string.IsNullOrEmpty(StockName))
                list = list.Where(x => x.StockName .Contains(StockName));

            if (!string.IsNullOrEmpty(mname))
                list = list.Where(x => x.MaterialCode.Contains(mname) || x.MaterialName.Contains(mname) || x.LocationCode.Contains(mname) || x.PalletBarcode.Contains(mname));

            if (status != 0)
                list = list.Where(x => x.Status == status);

            var lists = _inventoryRepository.GetEntityAlls(list, pageIndex, pageSize, out totalCount, x => x.CreateDate, false);
            var materpacklist = _materialPackageRepository.GetEntityAlls().ToList();
            var mlist = _materialRepository.GetAllEntityList();
            List<Inventory> invenlist = new List<Inventory>();
            foreach (var item in lists)
            {
                var materpackobj = materpacklist.FirstOrDefault(x => x.MaterialId == item.MaterialId);
                var mobj = mlist.FirstOrDefault(x => x.Id == item.MaterialId);
                Inventory invenobj = new Inventory();
                invenobj = mapper.Map<Inventory>(item);
                if(materpackobj != null)
                {
                    if(invenobj.AreaCode.Contains('P'))
                    {
                        //invenobj.AvailableQty = item.AvailableQty / materpackobj.ConversionFactor;
                        invenobj.AvailableQty = item.AvailableQty;
                    }
                    else if(invenobj.AreaCode.Contains('L'))
                    {
                        invenobj.UnitName = materpackobj.SubPackageUnitName;
                        invenobj.Articlebarcode = mobj?.ModelSpec;
                    }
                }
                invenlist.Add(invenobj);
            }
            return invenlist;
        }

        public List<InventoryExport>? GetInventoryExport(long aid, int status)
        {
            var list = _inventoryRepository.GetEntityAlls();
            if (status != 0)
                list = list.Where(x => x.Status == status);

            if(aid != 0)
                list = list.Where(x => x.AreaId == aid);
            var materpacklist = _materialPackageRepository.GetEntityAlls().ToList();
            List<InventoryExport> inventoryExports = new List<InventoryExport>();
            if (list.Any())
            {
                foreach (var item in list)
                {
                    var materpackobj = materpacklist.FirstOrDefault(x => x.MaterialId == item.MaterialId);
                    InventoryExport inventoryExport = new InventoryExport();
                    inventoryExport = mapper.Map<InventoryExport>(item);
                    if (item.Status == 1)
                        inventoryExport.Status = "正常库存";
                    else if (item.Status == 2)
                        inventoryExport.Status = "转移中的库存";
                    else if (item.Status == 3)
                        inventoryExport.Status = "入库在途";
                    else if (item.Status == 4)
                        inventoryExport.Status = "出库在途";
                    else if (item.Status == 5)
                        inventoryExport.Status = "限制使用的库存";
                    else if (item.Status == 6)
                        inventoryExport.Status = "异常库存";
                    else if (item.Status == 7)
                        inventoryExport.Status = "预分配库存";
                    else if (item.Status == 8)
                        inventoryExport.Status = "冻结库存";
                    if (materpackobj != null)
                    {
                        if (item.AreaCode.Contains('P'))
                        {
                            inventoryExport.AvailableQty = item.AvailableQty / materpackobj.ConversionFactor;
                        }
                        else if (item.AreaCode.Contains('L'))
                        {
                            inventoryExport.UnitName = materpackobj.SubPackageUnitName;
                        }
                    }
                    inventoryExports.Add(inventoryExport);
                }
                return inventoryExports;
            }
            return null;
        }

        public List<Inventory> GetInventoryGroupList(long? whId, long? aid, string? mname, int pageIndex, int pageSize, out int totalCount)
        {
            var list = _inventoryRepository.GetEntityAlls();

            if (whId != null)
                list = list.Where(x => x.WarehouseId == whId);

            if (aid != null)
                list = list.Where(x => x.AreaId == aid);

            if (!string.IsNullOrEmpty(mname))
                list = list.Where(x => x.MaterialCode.Contains(mname) || x.MaterialName.Contains(mname));

            var res = list
                        .GroupBy(s => s.MaterialId)
                        .Select(g => new Inventory()
                        {
                            Id = g.First().Id,
                            MaterialCode = g.First().MaterialCode,
                            MaterialName = g.First().MaterialName,
                            AvailableQty = (int)g.Sum(s => s.AvailableQty).GetValueOrDefault(),
                            CreateDate = g.First().CreateDate,
                        })
                        .OrderByDescending(x => x.CreateDate);
            var lists = _inventoryRepository.GetEntityAlls(res, pageIndex, pageSize, out totalCount, x => x.CreateDate, false);
            return lists.ToList();
        }

        public List<InventoryPalletDto> GetInventoryPalletDto(string? key, int pageIndex, int pageSize, out int totalCount)
        {
            var ilist = _inventoryRepository.GetEntityWhereAll(x => x.Status == 1 && x.IsLock == false && x.AreaCode=="2");

            if (!string.IsNullOrEmpty(key))
                ilist = ilist.Where(x => x.MaterialCode.Contains(key));

            var plist = _palletRepository.GetEntityWhereAll(x => x.Status == 1);

            var list = from a in ilist
                       join b in plist
                       on a.PalletBarcode equals b.PalletBarcode
                       select new InventoryPalletDto
                       {
                           Id = a.Id,
                           MaterialCode = a.MaterialCode,
                           MaterialId = a.MaterialId,
                           MaterialName = a.MaterialName,
                           BatchNo = a.BatchNo,
                           AvailableQty = a.AvailableQty,
                           LoadFactor = b.LoadFactor,
                           PalletBarcode = a.PalletBarcode,
                           LocationCode = a.LocationCode,
                       };
            totalCount = list.Count();
            return list.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
        }

        public List<InventoryPalletDto> GetInventoryPalletDto5(string? key, int pageIndex, int pageSize, out int totalCount)
        {
            var ilist = _inventoryRepository.GetEntityWhereAll(x => x.Status == 5 && x.IsLock == true && x.AreaCode.Contains('L'));

            if (!string.IsNullOrEmpty(key))
                ilist = ilist.Where(x => x.MaterialCode.Contains(key));

            var plist = _palletRepository.GetEntityWhereAll(x => x.Status == 1);

            var list = from a in ilist
                       join b in plist
                       on a.PalletBarcode equals b.PalletBarcode
                       select new InventoryPalletDto
                       {
                           Id = a.Id,
                           MaterialCode = a.MaterialCode,
                           MaterialId = a.MaterialId,
                           MaterialName = a.MaterialName,
                           BatchNo = a.BatchNo,
                           AvailableQty = a.AvailableQty,
                           LoadFactor = b.LoadFactor,
                           PalletBarcode = a.PalletBarcode,
                           LocationCode = a.LocationCode,
                       };
            totalCount = list.Count();
            return list.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
        }

        public List<InventoryWarn> GetInventoryWarnList(int? type, long? wid, long aid, int pageIndex, int pageSize, out int totalCount)
        {
            var mlist = _materialRepository.GetEntityAlls();
            var ilist = _inventoryRepository.GetEntityAlls().Where(x=>x.Status==1 && x.IsLock==false && x.AreaCode=="2");
            
            if (wid != null)
                ilist = ilist.Where(x => x.WarehouseId == wid);
            if (aid > 0)
                ilist = ilist.Where(x => x.AreaId == aid);
            List<InventoryWarn> iwlist = new List<InventoryWarn>();
            decimal ? availableQty = 0;
            int? maxsafetystock = 0;
            int? minsafetystock = 0;
            foreach (var item in ilist.ToList())
            {
                InventoryWarn ilobj = new InventoryWarn();
                availableQty = item.AvailableQty;
                maxsafetystock = mlist.FirstOrDefault(x => x.Id == item.MaterialId)?.MaxSafetyStock;
                minsafetystock = mlist.FirstOrDefault(x => x.Id == item.MaterialId)?.MinSafetyStock;             
                if (availableQty <= minsafetystock )
                {
                    ilobj = mapper.Map<InventoryWarn>(item);
                    ilobj.MaxSafetyStock= maxsafetystock;
                    ilobj.MinSafetyStock= minsafetystock;
                    ilobj.QTY = availableQty;
                    ilobj.WarnType = 1;
                    ilobj.WhId= item.WarehouseId;
                    ilobj.WhName = item.WarehouseName;
                    if(type!=null && type==1)
                        iwlist.Add(ilobj);
                    else if(type==null)
                        iwlist.Add(ilobj);
                }
                else if(availableQty >= maxsafetystock)
                {
                    ilobj = mapper.Map<InventoryWarn>(item);
                    ilobj.MaxSafetyStock = maxsafetystock;
                    ilobj.MinSafetyStock = minsafetystock;
                    ilobj.QTY = availableQty;
                    ilobj.WarnType = 2;
                    ilobj.WhId = item.WarehouseId;
                    ilobj.WhName = item.WarehouseName;
                    if (type != null && type == 2)
                        iwlist.Add(ilobj);
                    else if (type == null)
                        iwlist.Add(ilobj);
                }
                else if(item.ExpireDate!=null)
                {
                    if(item.CreateDate > item.ExpireDate)
                    {
                        ilobj = mapper.Map<InventoryWarn>(item);
                        ilobj.MaxSafetyStock = maxsafetystock;
                        ilobj.MinSafetyStock = minsafetystock;
                        ilobj.QTY = availableQty;
                        ilobj.WarnType = 3;
                        ilobj.WhId = item.WarehouseId;
                        ilobj.WhName = item.WarehouseName;
                        if (type != null && type == 3)
                            iwlist.Add(ilobj);
                        else if (type == null)
                            iwlist.Add(ilobj);
                    }
                }
            }
            totalCount = iwlist.Count;
            return iwlist;
        }

        public List<InventoryPalletDto> GetPickingShippingOrderDetail(string? key, int pageIndex, int pageSize, out int totalCount)
        {
            var ilist = _inventoryRepository.GetEntityWhereAll(x => x.Status == 3 && x.IsLock == false);
            ilist = ilist.Where(x => x.PalletBarcode == key);
            var plist = _palletRepository.GetEntityWhereAll(x => x.Status == 1);

            var list = from a in ilist
                       join b in plist
                       on a.PalletBarcode equals b.PalletBarcode
                       select new InventoryPalletDto
                       {
                           Id = a.Id,
                           MaterialCode = a.MaterialCode,
                           MaterialId = a.MaterialId,
                           MaterialName = a.MaterialName,
                           BatchNo = a.BatchNo,
                           AvailableQty = a.AvailableQty,
                           LoadFactor = b.LoadFactor,
                           PalletBarcode = a.PalletBarcode,
                           LocationCode = a.LocationCode,
                       };
            totalCount = list.Count();
            return list.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
        }

        public bool UpdInventoryStatus(long id,out string message)
        {
            message = string.Empty;
            var invobj = _inventoryRepository.QueryEntityById(id);
            if(invobj == null)
            {
                return false;
            }
            var frominobj = _inventoryRepository.QueryEntityWhere(x => x.AreaCode.Contains('P') && x.MaterialId == invobj.MaterialId && x.BatchNo == invobj.BatchNo && x.Status == 1 && x.IsLock == false);
            if (frominobj == null)
            {
                message = "整件库存不满足补货物资！";
                return false;
            }
            else
            {
                var matelpackobj = _materialPackageRepository.QueryEntityWhere(x => x.MaterialId == invobj.MaterialId);
                if (matelpackobj == null)
                {
                    message = "该物资打包明细有误！";
                    return false;
                }
                invobj.IsLock = true;
                invobj.Status = 5;
                invobj.Remark = "主动补货";
                frominobj.IsLock = true;
                frominobj.AllocateQty = matelpackobj.ConversionFactor;
                frominobj.PickedQty += matelpackobj.ConversionFactor;
                frominobj.Status = 5;
                ShippingReplenishment shippingReplenishment = new ShippingReplenishment
                {
                    BillType = 2,
                    MaterialId = invobj.MaterialId,
                    MaterialName = invobj.MaterialName,
                    FromWhId = frominobj.WarehouseId,
                    FromWhCode = frominobj.WarehouseCode,
                    FromWhName = frominobj.WarehouseName,
                    FromAreaId = frominobj.AreaId,
                    FromAreaCode = frominobj.AreaCode,
                    FromAreaName = frominobj.AreaName,
                    FromInventoryId = frominobj.Id,
                    FromCellId = frominobj.LocationId,
                    FromCellCode = frominobj.LocationCode,
                    FromCellName = frominobj.LocationName,
                    FromCellDepthIndex = frominobj.LocationDepth,
                    FromPalletBarcode = frominobj.PalletBarcode,
                    ToWhId = invobj.WarehouseId,
                    ToWhCode = invobj.WarehouseCode,
                    ToWhName = invobj.WarehouseName,
                    ToAreaId = invobj.AreaId,
                    ToAreaCode = invobj.AreaCode,
                    ToAreaName = invobj.AreaName,
                    ToInventoryId = invobj.Id,
                    ToCellId = invobj.LocationId,
                    ToCellCode = invobj.LocationCode,
                    ToCellName = invobj.LocationName,
                    ToCellDepthIndex = invobj.LocationDepth,
                    ToPalletBarcode = invobj.PalletBarcode,
                    AddQty = matelpackobj.ConversionFactor,
                    SubtractQty = matelpackobj.ConversionFactor,
                    Remark = "从" + frominobj.LocationName + "减出 " + matelpackobj.ConversionFactor.ToString() + " 补到" + invobj.LocationName
                };
                _shippingReplenishmentRepository.AddEntity(shippingReplenishment);
                return _unitOfWork.SaveChangesEntity();
            }
        }
    }
}
